// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2019-2020, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <mach/msgch_pro.h>
#include <linux/delay.h>
#define DEBUG
#include <linux/printk.h>

static struct task_struct *msgch_mutex_task;
static struct task_struct *msgch_spin_task;

static int msgch_mutex_thread(void *arg)
{
	int ret;
	msgch_snd_t snd_buf;
	msgch_rcv_t rcv_buf;

	while (1) {
		/* 1. test mutex transfer interface */
		/* 1.1 . wait forever */
		snd_buf.snd_buf.bits.type = MSGCH_CMD_TM;
		snd_buf.snd_buf.bits.st = 0x2;
		snd_buf.snd_buf.bits.wait = MSGCH_WAIT_FOREVER;

		ret = lombo_send_msg(&snd_buf, &rcv_buf,
					CHANNAL_MUTEX_INTERFACE);
		if (ret < 0) {
			pr_err("%s, %d, send msg with mutex interface to amu failed\n",
					__func__, __LINE__);
			return -EINVAL;
		}

		/* adjust the return value */
		if (rcv_buf.rcv_buf.bits.st != (snd_buf.snd_buf.bits.st + 1)) {
			pr_err("%s: %d, send msg using mutex interface error\n",
					__func__, __LINE__);
			return -EINVAL;
		}

		msleep(500);
		pr_info("%s: %d, mutex interface then wait forever succeeded\n",
			__func__, __LINE__);

		/* 1.2. wait some time */
		snd_buf.snd_buf.bits.type = MSGCH_CMD_TM;
		snd_buf.snd_buf.bits.st = 0x8;
		snd_buf.snd_buf.bits.wait = MSGCH_WAIT_TIME;
		/* set the timeout = 10 jiffies */
		snd_buf.time_l = 10;

		ret = lombo_send_msg(&snd_buf, &rcv_buf,
						CHANNAL_MUTEX_INTERFACE);
		if (ret < 0) {
			pr_err("%s, %d, send msg with mutex interface to amu failed\n",
					__func__, __LINE__);
			return -EINVAL;
		}

		/* adjust the return value */
		if (rcv_buf.rcv_buf.bits.st != (snd_buf.snd_buf.bits.st + 1)) {
			pr_err("%s: %d, send msg using mutex interface error, ret:%d, msg:%d\n",
			__func__, __LINE__, rcv_buf.rcv_buf.bits.st,
			snd_buf.snd_buf.bits.st);
			return -EINVAL;
		}

		msleep(500);
		pr_info("%s: %d, mutex interface then wait 100ms succeeded\n",
			__func__, __LINE__);
	}
}

static int msgch_spin_thread(void *arg)
{
	int ret;
	u64 timeout;
	msgch_snd_t snd_buf;
	msgch_rcv_t rcv_buf;

	while (1) {
		/* 2. test spin transfer interface */
		/* 2.1 wait forever */
		snd_buf.snd_buf.bits.type = MSGCH_CMD_TS;
		snd_buf.snd_buf.bits.st = 0x6;
		snd_buf.snd_buf.bits.wait = MSGCH_WAIT_FOREVER;

		ret = lombo_send_msg(&snd_buf, &rcv_buf,
						CHANNAL_SPIN_INTERFACE);
		if (ret < 0) {
			pr_err("%s, %d, send msg with spin interface to amu failed\n",
					__func__, __LINE__);
			return -EINVAL;
		}

		/* adjust the return value */
		if (rcv_buf.rcv_buf.bits.st != (snd_buf.snd_buf.bits.st + 1)) {
			pr_err("%s: %d, send msg using spin interface error\n",
					__func__, __LINE__);
			return -EINVAL;
		}

		msleep(500);

		pr_info("%s: %d, spin interface then busy wait forever succeeded\n",
				__func__, __LINE__);

		/* 2.2 wait some time  */
		snd_buf.snd_buf.bits.type = MSGCH_CMD_TS;
		snd_buf.snd_buf.bits.st = 0xa;
		snd_buf.snd_buf.bits.wait = MSGCH_WAIT_TIME;

		/* set the timeout = 100000000ns */
		timeout = 100000000;
		snd_buf.time_l = timeout & 0xffffffff;
		snd_buf.time_h = (timeout >> 32) & 0xffffffff;

		ret = lombo_send_msg(&snd_buf, &rcv_buf,
						CHANNAL_SPIN_INTERFACE);
		if (ret < 0) {
			pr_err("%s, %d, send msg with spin interface to amu failed\n",
					__func__, __LINE__);
			return -EINVAL;
		}

		/* adjust the return value */
		if (rcv_buf.rcv_buf.bits.st != (snd_buf.snd_buf.bits.st + 1)) {
			pr_err("%s: %d, send msg using spin interface error, ret:%d, msg:%d\n",
			__func__, __LINE__, rcv_buf.rcv_buf.bits.st,
			snd_buf.snd_buf.bits.st);
			return -EINVAL;
		}

		msleep(500);
		pr_info("%s: %d, spin interface then busy wait 100ms succeeded\n",
			__func__, __LINE__);
	}
}

void msgch_test(void)
{
	msgch_mutex_task = kthread_run(msgch_mutex_thread, NULL,
										"msgch_mutex_test");
	if (IS_ERR(msgch_mutex_task))
		pr_err("%s: %d, kthread run failed\n", __func__, __LINE__);

	msgch_spin_task = kthread_run(msgch_spin_thread, NULL,
										"msgch_spin_test");
	if (IS_ERR(msgch_spin_task))
		pr_err("%s: %d, kthread run failed\n", __func__, __LINE__);
}

